<?php

    /**
     * This file is part of the Intelligencer package.
     * For the full copyright and license, please view the LICENSE
     * file that was distributed with this source code.
     * 
     * @author         Roman Drapeko <roman.drapeko@gmail.com>
     * @copyright      Roman Drapeko <roman.drapeko@gmail.com>, 2009 - present
     */

    /**
     * Manager is responsible for asking Intelligencers in control state to load the classes.
     * @author drapeko
     */
    class itManager {
        
        protected $lastAvailableNullPriority = 1000000;
        protected $intelligencers = array();
        protected $logger = null;
        protected static $instance = null;
        
        /**
         * constructors
         * @return void
         */
        public function __construct() {
        }
        
        /**
         * Sets the logger
         * @param itLoggerI $logger
         * @return itManager itself
         */
        public function setLogger(itLoggerI $logger) {
            $this->logger = $logger;
            return $this;
        }
        
        /**
         * Returns the logger
         * @return itLoggerI
         */
        public function getLogger() {
            return $this->logger;
        }
        
        /**
         * Registers the autoloading function. It's done automatically when the new instance is being created.
         * @return void
         */
        public static function register() {
            spl_autoload_register(array(__CLASS__, 'autoload'));
        }
       
        /**
         * Unregisters the autoloading function. 
         * @return void
         */
        public static function unregister() {
            spl_autoload_unregister(array(__CLASS__, 'autoload'));
        }
        
        /**
         * Singleton. Returns the instance of the Manager.
         * @return itManager
         */
        public static function getInstance() {
            if (self::$instance == null) {
                self::$instance = new itManager();
                self::register();
            }
            
            return self::$instance;
        }
        
        /**
         * This function is called everytime the class loading attempt is made. 
         * It goes through all the intelligencers in control state ordered by priority and asks to load the class.
         * @param string $className the name of the class/interface
         * @return boolean 
         */
        public static function autoload($className) {
            return self::innerLoad(itManager::getInstance(), $className);
        }
        
        /**
         * It goes through all the intelligencers in control state ordered by priority and asks to load the class.
         * @param string $className the name of the class/interface
         * @return boolean
         */
        public function load($className) {
            return $this->innerLoad($this, $className);
        }
        
        protected static function innerLoad($manager, $className) {
            $intelligencers = $manager->intelligencers;
            
            foreach($intelligencers as $priority => $iArray) {
                foreach($iArray as $i) {
                    if ($i->inControl()) {
                        $loaded = $i->load($className);
                        if ($loaded == true) {
                            $manager->log("Intelligencer {$i->getName()} loaded '$className' class");
                            return true;
                        } else {
                            $manager->log("Intelligencer {$i->getName()} has not found '$className' class");
                        }
                    }
                }
            }
            
            return false;
        }
        
        /**
         * Sets the Intelligencer and returns the Intelligencer obj. The same as {@link setIntelligencerAndCreate}
         * @param itIntelligencer $i
         * @param int $priority null
         * @return itIntelligencer
         */
        public function addIntelligencerAndCreate(itIntelligencer $i, $priority = null) {
            $this->addIntelligencer($i, $priority);
            return $i;
        }
        
        /**
         * Sets the Intelligencer and returns the Intelligencer obj. The same as {@link addIntelligencerAndCreate}
         * @param itIntelligencer $i
         * @param int $priority null
         * @return itIntelligencer
         */
        public function setIntelligencerAndCreate(itIntelligencer $i, $priority = null) {
            $this->setIntelligencer($i, $priority);
            return $i;
        }
        
        /**
         * Sets the Intelligencer and returns itself. The same as {@link setIntelligencer}
         * @param itIntelligencer $i
         * @param int $priority null
         * @return itManager itself
         */
        public function addIntelligencer(itIntelligencer $i, $priority = null) {
            if ($this->hasIntelligencer($i)) {
                throw new itParameterException('This Intelligencer already exists in Manager. Remove it first.');
            }
            if (empty($priority)) {
                $priority = $this->lastAvailableNullPriority++;
            }
            
            if (!array_key_exists($priority, $this->intelligencers)) {
                $this->intelligencers[$priority] = array();
            }
            
            $this->intelligencers[$priority][] = $i;
            $i->setManager($this);
            ksort($this->intelligencers);
            
            return $this;
        }
        
        /**
         * Sets the Intelligencer and returns itself. The same as {@link addIntelligencer}
         * @param itIntelligencer $i
         * @param int $priority null
         * @return itManager itself
         */
        public function setIntelligencer(itIntelligencer $i, $priority = null) {
            return $this->addIntelligencer($i, $priority);
        }
        
        /**
         * Removes intelligencer by obj
         * @param itIntelligencer $i
         * @return itManager itself
         */
        public function delIntelligencer(itIntelligencer $val) {
            foreach ($this->intelligencers as $priority => $iArray) {
                foreach($iArray as $key => $i) {
                    if ($val === $i) {
                        unset($this->intelligencers[$priority][$key]);
                        ksort($this->intelligencers);
                        return $this;
                    }
                }
            }
            
            return $this;
        }
        
        /**
         * Returns intelligecer by name
         * @param string $name
         * @return itIntelligencer
         */
        public function getIntelligencerByName($name) {
            foreach($this->intelligencers as $iArray) {
                foreach($iArray as $i) {
                    if ($i->getName() == $name) {
                        return $i;
                    }
                }
            }
            
            return null;
        }
        
        /**
         * Checks whether Intelligencer exists by name
         * @param string $name
         * @return boolean
         */
        public function hasIntelligencerByName($name) {
            foreach($this->intelligencers as $iArray) {
                foreach($iArray as $i) {
                    if ($i->getName() == $name) {
                        return true;
                    }
                }
            }
            
            return false;
        }
        
        /**
         * Checks whether Intelligencer exists by obj
         * @param itIntelligencer $name
         * @return boolean
         */
        public function hasIntelligencer(itIntelligencer $i) {
            foreach($this->intelligencers as $iArray) {
                if (itUtil::inArray($i, $iArray)) {
                    return true;
                }
            }
            
            return false;
        }
        
        /**
         * Removes all the intelligencers from the manager
         * @return itManager itself
         */
        public function clear() {
            foreach($this->intelligencers as $iArray) {
                foreach($iArray as $i) {
                    $i->destroy();
                }
            }
            
            $this->intelligencers = array();
            return $this;
        }
        
        protected function log($str) {
            if ($this->logger != null) {
                $this->logger->debug($str);
            }
        }
    }
    
?>